/*
 *	Copyright (C) 2008 CRIMERE
 *	Copyright (C) 2008 Jean-Marc Mercier
 *	
 *	This file is part of OTS (optimally transported schemes), an open-source library
 *	dedicated to scientific computing. http://code.google.com/p/optimally-transported-schemes/
 *
 *	CRIMERE makes no representations about the suitability of this
 *	software for any purpose. It is provided "as is" without express or
 *	implied warranty.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#if !defined(_Function_Utilities_)
#define _Function_Utilities_

/*! This file collect facilities for functions. 
*/

/* /brief template utility to define a function starting from a smart pointer
*/
template <class function>
struct smart_ptr_function {
	typedef typename function::argument_type	argument_type;
	typedef typename function::result_type		result_type;
	smart_ptr_function() {};
	smart_ptr_function(smart_ptr<function> &function) : function_ptr_(function)
	{
		function_ = &*function_ptr_;
	}
	void set_function(smart_ptr<function> &function){
		function_ptr_ = function;
		function_ = &*function_ptr_;
	};
	result_type operator()(const argument_type & d) const {return (*function_)(d);};
	smart_ptr<function> function_ptr_;
	function * function_; 
};



/* /brief template utility for function defined over integral type
	
	starting from a function defining an operator
	integral_type operator()(const integral_type& from, double time) const
	this template defines recursively a general operator
	template <class data,class result>
	result operator()(const data& from) const
*/
template <class function>
class template_function_utility : public function
{
public :
	typedef function								Base;
	typedef template_function_utility				type;
	typedef typename Base::argument_type			argument_type;
	typedef typename Base::result_type				result_type;
	typedef typename function::argument_base_type argument_base_type;

	type() {};
	template <class A>
	type(const A& a) : Base(a) {};
	template <class A, class B>
	type(const A& a, const B&b) : Base(a,b) {};
public :
	inline result_type operator()(argument_base_type from) const {
		return Base::operator()(from);
	};
	template <class data,class result>
	result operator()(const data& from) const {
		result returned(from.size());
		Apply<data,result>(from,returned,*this);
		return returned;
	};
private :
	template <class data,class result>
	struct Apply {
		Apply(const data& from, result &returned, const type& which) 
		{
			typedef data::iterator iterator;
			typedef data::const_iterator const_iterator;
			typedef data::value_type	data_value_type;
			typedef result::value_type	result_value_type;
			const_iterator begin = from.begin(), end = from.end();
			iterator beg = returned.begin();
			for (;begin != end;++begin,++beg)
				Apply<data_value_type,result_value_type>(*begin,*beg,which);
		};
	};
	template <>
	struct Apply<argument_base_type,result_type> {
		Apply(const argument_base_type& from, result_type &returned, const type& which) 
		{
			returned = which.Base::operator()(from);
		};
	};
};
/* /brief template utility for function defined over integral type
	
	starting from a function defining an operator
	integral_type operator()(const integral_type& from, double time) const
	this template defines recursively a general operator
	template <class data,class result>
	result operator()(const data& from, double time) const
*/
template <class function>
class template_time_function_utility : public function
{
public :
	typedef function								Base;
	typedef template_time_function_utility			type;
	typedef typename Base::result_type				result_type;
//	typedef typename function::argument_base_type argument_base_type;
	typedef typename function::first_argument_type first_argument_type;
	typedef typename function::second_argument_type second_argument_type;
	
	type(){};
	template <class A>
	type(const A& a) : Base(a) {};
	template <class A, class B>
	type(const A& a, const B&b) : Base(a,b) {};
public :
	template <class data,class result>
	result operator()(const data& from, second_argument_type time) const {
		result returned(from.size());
		Apply<data,result,boost::is_fundamental<data>::type>(from,returned,*this,time);
		return returned;
	};
	virtual result_type operator()(first_argument_type from, second_argument_type time) const {
		return Base::operator()(from,time);
	};
private :
	template <class data,class result,class is_fundamental>
	struct Apply {
		Apply(const data& from, result& result, const type& which, second_argument_type time)
		{
			typedef data::iterator iterator;
			typedef data::const_iterator const_iterator;
			typedef data::value_type			data_value_type;
			typedef result::value_type			result_value_type;
			const_iterator begin = from.begin(), end = from.end();
			iterator beg = result.begin();
			for (;begin != end;++begin,++beg)
				Apply<result_value_type,data_value_type,boost::is_fundamental<data_value_type>::type>(*begin,*beg,which, time);
		};
	};
	template <class data,class result>
	struct Apply<data,result, OS_true> {
		Apply(data from, result &returned, const type& which, second_argument_type time)
		{
			returned = which(from,time);
		};
	};
};

/* /brief template utility for function defined over integral type
	
	starting from a function defining an operator
	integral_type operator()(const integral_type& from, double time) const
	this template defines recursively a general operator
	template <class data,class result>
	result operator()(const data& from) const
*/
template <class function>
class template_function_utility_0 : public function
{
public :
	typedef function								Base;
	typedef template_function_utility_0				type;
	type() {};
	template <class A>
	type(const A& a) : Base(a) {};
	template <class A, class B>
	type(const A& a, const B&b) : Base(a,b) {};
public :
	template <class data>
	void operator()(const data& from) const {
			typedef data::iterator iterator;
			typedef data::value_type	data_value_type;
			const_iterator begin = from.begin(), end = from.end();
			iterator beg = returned.begin();
			for (;begin != end;++begin,++beg)
				*begin = (*this).Base::operator()();
	};
};


#endif